perm filename PUPRTE.BPL[11,HE] blob sn#656323 filedate 1982-04-29 generic text, type T, neo UTF8
// PUPRTE.BPL -- MODULE IMPLEMENTING THE PUP ROUTING TABLE
// Copyright Xerox Corporation 1979

GET "PUPLIB.HDR"
GET "LEVEL0.HDR"
GET "LEVEL1.HDR"

MANIFEST
[
LENRT = 129
]

MANIFEST
[
RTTIMEOUTINTERVAL = 900		//AGE RTE'S AFTER 1.5 MINUTES
				//PURGE THEM AFTER 3 MINUTES
RTSIZE = 32
PROBEMASK = RTSIZE-1

// ROUTING INFO PROTOCOL DEFINITIONS
PSROUTEINFO = 2
PTROUTEREQUEST = #200
PTROUTEREPLY = #201
]

// THIS MODULE PLUGS INTO GATEFORWARD.BCPL - THE GATEWAY FORWARDER,
//  OR INTO PUPDUMMYGATE, IF THIS ISN'T A GATEWAY.

//----------------------------------------------------------------------------
LET INITROUTINGTABLE(ZONE) BE
//----------------------------------------------------------------------------
[
PUPRT := ALLOCATE(ZONE, LENRT)
SETBLOCK(LV PUPRT!1, RTFREEENTRY, RTSIZE*LENRTE)
PUPRT!0 := LOGRTSIZE
]

//----------------------------------------------------------------------------
AND HLOOKUP(RT, KEY, FINDFREE) = VALOF
//----------------------------------------------------------------------------
//RETURNS POINTER TO RTE MATCHING KEY, OR ZERO IF NOT FOUND.
//IF FINDFREE IS TRUE, THEN UPON FAILURE RETURNS POINTER TO
//FIRST FREE ENTRY (ZERO IF NONE).
[
LET IPROBE = NIL
LET INCREMENT = HHASH(LOGRTSIZE, KEY, LV IPROBE)
LET PROBE = IPROBE
   [
   LET RTE = LV RT!(LENRTE*PROBE+1)
   IF KEY EQ RTE!NET THEN RESULTIS RTE  //MATCH
   IF RTE!NET EQ RTFREEENTRY THEN
      TEST FINDFREE
         THEN RESULTIS RTE  //FREE ENTRY
         OR RESULTIS 0
   PROBE := (PROBE+INCREMENT) & PROBEMASK
   ] REPEATUNTIL PROBE EQ IPROBE
RESULTIS 0  //FAIL.  SEARCHED THE WHOLE TABLE
]


//----------------------------------------------------------------------------
AND HENUMERATE(RT, PROC, ARG) BE
//----------------------------------------------------------------------------
[
//CALLS PROC(RTE, ARG) FOR EVERY VALID ENTRY IN RT
FOR I = 0 TO RTSIZE-1 DO
   [
   IF RT!(4*I+1+NET) GE 0 THEN PROC(LV RT!(4*I+1), ARG)
   ]
]


//----------------------------------------------------------------------------
AND HINSERT(RT, KEY) = VALOF
//----------------------------------------------------------------------------
//RETURNS POINTER TO AN RTE WHERE KEY CAN BE INSERTED.
//KEY IS IN THE NET FIELD AND THE REST OF THE RTE IS ZEROED.
[
LET RTE = HLOOKUP(RT, KEY, TRUE)
IF RTE EQ 0 THEN SYSERR(PUPRT, ECPUPRTFULL)  //NO FREE ENTRIES
ZERO(RTE, LENRTE)
RTE!NET := KEY
RESULTIS RTE
]

//----------------------------------------------------------------------------
AND HDELETE(RT, KEY) BE
//----------------------------------------------------------------------------
[
LET RTE = HLOOKUP(RT, KEY, FALSE)
IF RTE NE 0 THEN
   [  //MARK ENTRY FREE, THEN REPEATEDLY ENUMERATE THE RT,
      //REHASHING INACCESSIBLE ENTRIES UNTIL ALL ENTRIES ARE
      //ACCESSIBLE.
   LET DONE = NIL
   RTE!NET := RTFREEENTRY
      [
      DONE := TRUE
      FOR I = 0 TO RTSIZE-1 DO
         [
         RTE := LV RT!(4*I+1)
         IF RTE!NET NE RTFREEENTRY THEN
            [
            LET NEWRTE = HLOOKUP(RT, RTE!NET, TRUE)
            IF NEWRTE!NET EQ RTFREEENTRY THEN
               [
               MOVEBLOCK(NEWRTE, RTE, LENRTE)
               RTE!NET := RTFREEENTRY
               DONE := FALSE
               BREAK
               ]

            ]
         ]
      ] REPEATUNTIL DONE
   ]   
]

//----------------------------------------------------------------------------
AND GATEWAYLISTENER() BE
//----------------------------------------------------------------------------
// THIS PROCESS LISTENS FOR GRATUITOUS ROUTING TABLE BROADCASTS FROM
//  GATEWAYS AND UPDATES OUR LOCAL ROUTING TABLE.
// IF WE ARE A GATEWAY, ALSO LISTENS FOR GATEWAY INFO REQUESTS
//  AND RESPONDS APPROPRIATELY.
// PURGES ROUTING TABLE ENTRIES THAT HAVEN'T BEEN UPDATED RECENTLY.
// GENERATES GATEWAY ROUTING INFO PROBES IF UNKNOWNNET IS NONZERO.
[
LET RECENTPROBEFLAG = NIL
LET UPDATETIMER = NIL; SETTIMER(LV UPDATETIMER, 0)
   [
   IF TIMERHASEXPIRED(LV UPDATETIMER) THEN
      [
      //EVERY 10 SECONDS AGE THE RT ENTRIES
      HENUMERATE(PUPRT, AGERTE, PUPRT)
      RECENTPROBEFLAG := FALSE
      SETTIMER(LV UPDATETIMER, 100)
      ]

   WHILE GATEWAYLISTENERSOC!IQHEAD NE 0 DO
      [
      LET PBI = DEQUEUE(LV GATEWAYLISTENERSOC!IQ)
      TEST (PBI!TYPE & #377) EQ PTROUTEREPLY
         THEN
            [
            TEST (PBI!SHOST & #377) NE (PBI!NDB)!LHOST
            THEN
               [
               PROCESSROUTEINFOREPLY(PBI)  //IGNORE OUR OWN BCSTS
               ]
            OR
               [
               RELEASEPBI(PBI)
               ]
            ]
         OR
            [
            FORWARDER(PBI)  // MAYBE THE GATEWAY KNOWS HOW TO HANDLE IT
            ] 
      ]

   IF UNKNOWNNET NE 0 & NOT RECENTPROBEFLAG THEN
      [
      //BROADCAST A ROUTING INFO REQUEST ON EACH
      //DIRECTLY-CONNECTED NETWORK
      LET PBI = GETPBI(GATEWAYLISTENERSOC, TRUE)
      IF PBI NE 0 THEN
         [
         PBI!STATUS := PBI!STATUS | #40000
         COMPLETEPUP(PBI, PTROUTEREQUEST, PUPOVBYTES)
         UNKNOWNNET := 0
         RECENTPROBEFLAG := TRUE
         ]
      ]

   FORWARDERCTX()  // LET THE GATEWAY FORWARD SOME PACKETS
   ] REPEAT
]

//----------------------------------------------------------------------------
AND AGERTE(RTE, RT) BE
//----------------------------------------------------------------------------
IF (RTE!HOPS & #77400) NE 0 & TIMERHASEXPIRED(LV RTE!RTETIMER) THEN
   TEST (RTE!RECENT & #100000)
      THEN  //FIRST TIMEOUT, MAKE ENTRY ELIGIBLE FOR REPLACEMENT
         [
         RTE!RECENT := RTE!RECENT & #77777
         SETTIMER(LV RTE!RTETIMER, RTTIMEOUTINTERVAL)
         ]
      OR HDELETE(RT, RTE!NET)  //SECOND TIMEOUT, PURGE ENTRY

//----------------------------------------------------------------------------
AND PROCESSROUTEINFOREPLY(PBI) BE
//----------------------------------------------------------------------------
// UPDATE LOCAL RT WITH STUFF IN IMAGATEWAY PUP.
// NOTE THAT THE IDENTITY OF THE DIRECTLY CONNECTED NET HAS ALREADY BEEN
// ESTABLISHED IN PUPLEVEL1, IF IT WASN'T PREVIOUSLY KNOWN.  HERE WE UPDATE
// OUR RT AS APPROPRIATE WITH EACH OF THE 4-BYTE INFO BLOCKS IN THE PUP.
[
LET NET = PBI!DNET RSHIFT 8	//DIRECTLY CONNECTED NET
LET GHOST = (PBI!SHOST & #377)	//GATEWAY HOST ON NET
IF NET NE 0 & PBI!(SSOCKET+0) EQ 0 &	// JUST BEING SUSPICIOUS...
 PBI!(SSOCKET+1) EQ PSROUTEINFO THEN
   FOR C = 1 TO PBI!LENGTH-PUPOVBYTES BY 4 DO
      [
      // COMPUTE OUR HOP COUNT TO TARGET NET VIA THIS GATEWAY.
      LET GHOPS = MIN((PBI!(WORDS+(C+1)/2) & #377), MAXHOPS)+1
      LET RTE = NIL

      // LOOK UP TARGET NET IN RT.
      NET := PBI!(WORDS+(C-1)/2) RSHIFT 8
      RTE := HLOOKUP(PUPRT, NET, FALSE)
      TEST RTE EQ 0
         THEN
            [
            // TARGET NET NOT IN RT.
            // IF TARGET NET IS INACCESSIBLE, DON'T INSERT NEW RTE FOR IT.
            IF GHOPS GR MAXHOPS LOOP
            RTE := HINSERT(PUPRT, NET)  // SETS ENTIRE RTE TO ZERO
            ]
         OR

            // TARGET NET ALREADY IN RT.  IF DIRECTLY CONNECTED, DO NOTHING.
            IF (RTE!HOPS & #77400) EQ 0 LOOP

      // UPDATE RT ENTRY WITH THIS INFO BLOCK IF
      // (1) AN RTE DIDN'T PREVIOUSLY EXIST FOR THIS NET, OR
      // (2) THE EXISTING ENTRY HAS TIMED OUT (RECENT = FALSE), OR
      // (3) THE NEW GATEWAY NET/HOST IS THE SAME AS IN THE RTE, OR
      // (4) THE NEW ROUTE HAS FEWER HOPS THAN THE EXISTING ONE.
      // NOTE THAT IF (1) WAS TRUE, A NEW RTE WILL HAVE BEEN CREATED (ABOVE),
      // WITH CONTENTS ZEROED OUT, WHICH WILL SATISFY (2) HERE.
      IF (RTE!RECENT & #100000) EQ FALSE |  // (2)
       ((PBI!NDB EQ RTE!DNDB) & (GHOST EQ (RTE!HOST & #377))) |  // (3)
       GHOPS LS ((RTE!HOPS & #77400) RSHIFT 8) THEN  // (4)
         [
         // NOTE WHETHER ANYTHING HAS REALLY CHANGED.
         UNLESS GHOPS EQ ((RTE!HOPS & #77400) RSHIFT 8) DO PUPRTCHANGED := TRUE

         // INSERT ROUTE INTO RTE.
         RTE!HOST := (RTE!HOST & #100000) + (GHOPS LSHIFT 8) + GHOST
         RTE!DNDB := PBI!NDB  //RT->NDB

         // RESET RTE TIMEOUT ONLY IF THE TARGET NET IS NOW ACCESSIBLE.
         // THE IDEA IS TO CAUSE PERMANENTLY INACCESSIBLE NETS EVENTUALLY
         // TO BE PURGED.  ACTUALLY, IN NON-GATEWAY HOSTS, WE COULD PURGE
         // INACCESSIBLE NETS IMMEDIATELY;  HOWEVER, KNOWLEDGE OF A NETWORK'S
         // INACCESSIBILITY MUST BE REMEMBERED FOR A WHILE BY GATEWAY HOSTS
         // AND PASSED AMONG THEM EXPLICITLY SO THAT ALTERNATE ROUTES WILL
         // BE DISCOVERED QUICKLY.
         IF GHOPS LE MAXHOPS THEN
            [
            RTE!RECENT := RTE!RECENT | #100000  //RECENTLY UPDATED
            SETTIMER(LV RTE!RTETIMER, RTTIMEOUTINTERVAL)
            ]
         ]
      ]
RELEASEPBI(PBI)
]